package auto

import (
	"fmt"
	"gitee.com/huanminabc/go-utils/file"
	"github.com/stitch-june/selenium"
	"github.com/stitch-june/selenium/chrome"
	"os"
	"time"
)

type StartConfig func(c *Config)

// SetShowLog 设置是否开启日志
func SetShowLog(show bool) StartConfig {
	return func(c *Config) {
		c.ShowLog = show
	}
}

// SetDriverPath 设置 Driver 路径
func SetDriverPath(path string) StartConfig {
	return func(c *Config) {
		c.DriverPath = path
	}
}

// SetDriverPort 设置端口
func SetDriverPort(port int) StartConfig {
	return func(c *Config) {
		c.DriverPort = port
	}
}

// SetBrowserName 设置游览器名称
func SetBrowserName(name string) StartConfig {
	return func(c *Config) {
		c.BrowserName = name
	}
}

// SetServiceOption 设置配置
func SetServiceOption(option selenium.ServiceOption) StartConfig {
	return func(c *Config) {
		c.ServiceOption = append(c.ServiceOption, option)
	}
}

// SetHeadless 设置无头
func SetHeadless() StartConfig {
	return func(c *Config) {
		c.Args = append(c.Args, "--headless")
	}
}

// ERROR:device_event_log_impl.ccBluetooth:bluetooth_adapter_winrt.ccGetting Default Adapter failed.解决办法

type Config struct {
	ShowLog       bool                     // 是否打印日志到控制台
	DriverPath    string                   // 驱动路径
	DriverPort    int                      // 浏览器端口
	BrowserName   string                   // 浏览器名字
	ServiceOption []selenium.ServiceOption // 启动配置
	Args          []string                 // 启动 selenium 的配置
}

// NewDriver 创建 service、driver
func NewDriver(config *Config, startConfig ...StartConfig) (service *selenium.Service, driver selenium.WebDriver) {
	var err error

	// 通过 Set 来的修改配置
	for _, sc := range startConfig {
		sc(config)
	}

	// 打印日志判断
	if config.ShowLog {
		config.ServiceOption = append(config.ServiceOption, selenium.Output(os.Stdout))
	}

	// 启动 selenium
	service, err = selenium.NewChromeDriverService(config.DriverPath, config.DriverPort, config.ServiceOption...)
	if err != nil {
		service.Stop()
		panic(err)
	}

	// 启动配置，Args 可以 --headless 之类
	cps := selenium.Capabilities{"browserName": config.BrowserName}
	if len(config.Args) != 0 {
		cps.AddChrome(chrome.Capabilities{
			Args: config.Args,
		})
	}

	// 获取 driver
	driver, err = selenium.NewRemote(
		cps,
		fmt.Sprintf("http://localhost:%d/wd/hub", config.DriverPort),
	)
	if err != nil {
		panic(err)
	}

	return service, driver
}

// 滚动指定元素到可见区域,前提元素已经加载完成能够定位到
func ScrollElementToView(driver selenium.WebDriver, element selenium.WebElement) {

	//获取当前滚动条高度
	newIntHeight, err := driver.ExecuteScript("return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;", nil)
	if err != nil {
		panic(err)
	}
	//获取当前元素的高度
	elementHeight, err := element.Size()
	if err != nil {
		panic(err)
	}
	//获取当前元素的位置
	elementLocation, err := element.Location()
	if err != nil {
		panic(err)
	}
	//判断当前元素是否在可见区域
	if float64(elementLocation.Y) > newIntHeight.(float64) && float64(elementLocation.Y) < newIntHeight.(float64)+float64(elementHeight.Height) {
		return
	}
	//滚动到可见区域
	driver.ExecuteScript("arguments[0].scrollIntoView(true);", []interface{}{element})
}

// 持续滚动指定元素到页面最底部
/**
 * @param driver selenium.WebDriver
 * @param element selenium.WebElement
 * @param speed time.Duration 滚动速度
 */
func ScrollViewBottom(driver selenium.WebDriver, speed time.Duration) {
	//定义一个初始值
	var intHeight = 0.0
	//获取当前滚动条高度
	newIntHeight, err := driver.ExecuteScript("return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;", nil)
	if err != nil {
		panic(err)
	}
	//结果是interface{}类型,需要转换成float64
	intHeight = newIntHeight.(float64)
	//循环滚动到底部
	for {
		driver.ExecuteScript("window.scrollTo(0, document.body.scrollHeight)", nil)
		newIntHeight, err = driver.ExecuteScript("return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;", nil)
		if err != nil {
			panic(err)
		}
		//判断滚动条高度是否相等,相等说明到底部了,退出循环
		if intHeight == newIntHeight.(float64) {
			break
		}
		intHeight = newIntHeight.(float64)
		time.Sleep(speed)
	}
}

// 当前屏幕截图
func ScreenShot(driver selenium.WebDriver, path string) {
	//截图
	screenShot, err := driver.Screenshot()
	if err != nil {
		panic(err)
	}
	//保存图片
	file.WriteFileByte(path, false, screenShot)
	if err != nil {
		panic(err)
	}
}

// 指定元素截图
func ScreenShotElement(element selenium.WebElement, path string) {
	//截图
	screenShot, err := element.Screenshot(true) //true表示只截取元素的可见区域
	if err != nil {
		panic(err)
	}
	//保存图片
	file.WriteFileByte(path, false, screenShot)
	if err != nil {
		panic(err)
	}
}
